package com.shangxian.giveithome.utils;

import cn.hutool.core.util.StrUtil;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.shangxian.giveithome.code.ImgFeiCode;
import com.shangxian.giveithome.entity.petCard.PetCardQrCode;
import com.shangxian.giveithome.exception.ExceptionUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.csource.common.MyException;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author coderFu
 * @create 2021/5/4
 */
@Slf4j
public class PetCardCodeUtils {
    /**
     * CODE_WIDTH：二维码宽度，单位像素
     * CODE_HEIGHT：二维码高度，单位像素
     * FRONT_COLOR：二维码前景色，0x000000 表示黑色
     * BACKGROUND_COLOR：二维码背景色，0xFFFFFF 表示白色
     * 演示用 16 进制表示，和前端页面 CSS 的取色是一样的，注意前后景颜色应该对比明显，如常见的黑白
     */
    /**
     * 生成二维码的路径（内容）
     */
    private static final String URL = "https://app.shangxianruanjian.cn/page?id=";

    private static final int ALPHA = 10;
    /**
     * 中间logo的高度
     */
    private static final int WIDTH = 60;
    private static final int HEIGHT = 60;
    /**
     * 二维码的大小
     */
    private static final int CODE_WIDTH = 400;
    private static final int CODE_HEIGHT = 400;
    /**
     * 二维码的背景颜色
     */
    private static final int FRONT_COLOR = 0x000000;
    private static final int BACKGROUND_COLOR = 0x00FFFF;

    /**
     * 文字内容：扫码查看宠物信息
     */
    private static final int  WORD_HEIGHT = 425;
    private static final String WORDS =  "扫码查看宠物信息";
    /**
     * 文字内容：扫码查看宠物信息
     */
    private static final int HUNDREADS = 100;


    public  static PetCardQrCode produceOneQr(Integer n) throws IOException {
        PetCardCodeUtils petCardCodeUtils = new PetCardCodeUtils();
        int i = n.toString().length();
        String filename = "";
        if (i==1){
            filename = "00000"+n;
        }else if (i==2){
            filename = "0000"+n;
        }else if (i==3){
            filename = "000"+n;
        }else if (i==4){
            filename ="00"+n;
        }else if(i==5){
            filename = "0"+n;
        }
        PetCardQrCode petCardCodeQr = petCardCodeUtils.createPetCardCodeQr(n);
        petCardCodeQr.setPetCardNo(filename);
        return petCardCodeQr;
    }

    public static ArrayList<PetCardQrCode> produceHundredsQr(int n){
        PetCardCodeUtils petCardCodeUtils = new PetCardCodeUtils();
        ArrayList<PetCardQrCode> list = new ArrayList<PetCardQrCode>();
        PetCardQrCode petCardQrCode = new PetCardQrCode();
        for (Integer j =n; j<=n+HUNDREADS; j++){
            int i = j.toString().length();
            String filename = "";
            if (i==1){
                filename = "00000"+j;
            }else if (i==2){
                filename = "0000"+j;
            }else if (i==3){
                filename = "000"+j;
            }else if (i==4){
                filename ="00"+j;
            }else if(i==5){
                filename = "0"+j;
            }
            try {
                petCardQrCode = petCardCodeUtils.createPetCardCodeQr(j);
                petCardQrCode.setPetCardNo(filename);
                list.add(petCardQrCode);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return list;
    }


    public PetCardQrCode createPetCardCodeQr(int n) throws IOException {
        PetCardQrCode petCardQrCode = new PetCardQrCode();
        BufferedImage bufferedImage = null;
        /**com.google.zxing.EncodeHintType：编码提示类型,枚举类型
         * EncodeHintType.CHARACTER_SET：设置字符编码类型
         * EncodeHintType.ERROR_CORRECTION：设置误差校正
         *      ErrorCorrectionLevel：误差校正等级，L = ~7% correction、M = ~15% correction、Q = ~25% correction、H = ~30% correction
         *      不设置时，默认为 L 等级，等级不一样，生成的图案不同，但扫描的结果是一样的
         * EncodeHintType.MARGIN：设置二维码边距，单位像素，值越小，二维码距离四周越近
         * */
        Map<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET,"UTF-8");
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
        hints.put(EncodeHintType.MARGIN,1);
        /**
         * MultiFormatWriter:多格式写入，这是一个工厂类，里面重载了两个 encode 方法，用于写入条形码或二维码
         *      encode(String contents,BarcodeFormat format,int width, int height,Map<EncodeHintType,?> hints)
         *      contents:条形码/二维码内容
         *      format：编码类型，如 条形码，二维码 等
         *      width：码的宽度
         *      height：码的高度
         *      hints：码内容的编码类型
         * BarcodeFormat：枚举该程序包已知的条形码格式，即创建何种码，如 1 维的条形码，2 维的二维码 等
         * BitMatrix：位(比特)矩阵或叫2D矩阵，也就是需要的二维码
         */
        MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
        BitMatrix bitMatrix = null;
        try {
            bitMatrix = multiFormatWriter.encode(URL+n, BarcodeFormat.QR_CODE,CODE_WIDTH,CODE_HEIGHT,hints);
        /**java.awt.image.BufferedImage：具有图像数据的可访问缓冲图像，实现了 RenderedImage 接口
         * BitMatrix 的 get(int x, int y) 获取比特矩阵内容，指定位置有值，则返回true，将其设置为前景色，否则设置为背景色
         * BufferedImage 的 setRGB(int x, int y, int rgb) 方法设置图像像素
         *      x：像素位置的横坐标，即列
         *      y：像素位置的纵坐标，即行
         *      rgb：像素的值，采用 16 进制,如 0xFFFFFF 白色
         */
        bufferedImage = new BufferedImage(CODE_WIDTH, CODE_HEIGHT, BufferedImage.TYPE_4BYTE_ABGR);
        for (int x = 0; x < CODE_WIDTH; x++) {
            for (int y = 0; y < CODE_HEIGHT; y++) {
                bufferedImage.setRGB(x, y, bitMatrix.get(x, y) ? FRONT_COLOR : BACKGROUND_COLOR);
            }
        }
        BufferedImage bufferedImage1 = transparentImage(bufferedImage);
        BufferedImage bufferedImage2 = insertWords(bufferedImage1);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ImageIO.write(bufferedImage2,"png",bos);
           //File file = new File(n+".png");
            //ImageIO.write(bufferedImage2, "png",file);
        byte[] bytes = bos.toByteArray();
        String path = uploadFile(bytes, "png", null);
        petCardQrCode.setState(0);
        petCardQrCode.setPath(path);
        petCardQrCode.setContent(URL+n);
        petCardQrCode.setCreateTime(new Date());
        }catch (Exception e) {
        e.printStackTrace();
        }
        return petCardQrCode;
    }



    public static BufferedImage transparentImage(BufferedImage srcImage
                                                ) throws IOException {
        //取得图片的长和宽
        int imgHeight = srcImage.getHeight();
        int imgWidth = srcImage.getWidth();
        int c = srcImage.getRGB(3, 3);
        //把原图片的内容复制到新的图片，同时把背景设为透明
        //新建一个类型支持透明的BufferedImage
        BufferedImage tmpImg = new BufferedImage(imgWidth, imgHeight,BufferedImage.TYPE_4BYTE_ABGR);
        for(int i = 0; i < imgWidth; ++i)
        {
            for(int j = 0; j < imgHeight; ++j){
                //把背景设为透明
                if(srcImage.getRGB(i, j) == c){
                    tmpImg .setRGB(i, j, c & 0x00ffffff);
                }
                //设置透明度
                else{
                    int rgb = tmpImg .getRGB(i, j);
                    rgb = ((ALPHA * 255 / 10) << 24) | (rgb & 0x00ffffff);
                    tmpImg .setRGB(i, j, rgb);
                }
            }
        }
        return tmpImg ;
    }
    /**
     *二维码下方插入文字
     * @param source 图片处理对象
     */
    public  BufferedImage  insertWords(BufferedImage source) {
        //新的图片在二维码下方加入文字说明
        BufferedImage outImage = new BufferedImage(CODE_WIDTH,WORD_HEIGHT, BufferedImage.TYPE_INT_ARGB);
        //获取绘图对象
        Graphics2D outg = outImage.createGraphics();
        //画二维码到新的面板
        outg.drawImage(source,0,0,source.getWidth(),source.getHeight(),null);
        //画文字到新的面板
        // Color color = new Color(183,183,183 );
        //设置颜色和画笔粗细
        outg.setColor(Color.black);
        outg.setStroke(new BasicStroke(5));
        //字体、字型、字号
        outg.setFont(new Font("微软雅黑",Font.PLAIN,18));
        //文字长度
        int strWidth = outg.getFontMetrics().stringWidth(WORDS);
        //总长度减去文字长度的一半（居中显示）
        int wordStartX= (CODE_WIDTH-strWidth)/2;
        //height+(outImage.getHeight()-height)/2+12
        int wordStartY = CODE_HEIGHT+10;
        //画文字
        outg.drawString(WORDS,wordStartX,wordStartY);
        outg.dispose();
        outImage.flush();
        return outImage;
    }
    /**
     * fastdfs 上传文件
     * @param bytes
     * @param ext_Name
     * @param file_Name
     * @return
     */
    private String uploadFile(byte[] bytes, String ext_Name, String file_Name) {
        StringBuilder stringBuilder = new StringBuilder();
        try {
            ClientGlobal.initByProperties("fastdfs.properties");
            TrackerClient trackerClient = new TrackerClient();
            TrackerServer trackerServer = trackerClient.getTrackerServer();
            String storageServerIp = getStorageServerIp(trackerClient, trackerServer);
            StorageServer storageServer = getStorageServer(storageServerIp);
            StorageClient storageClient = new StorageClient(trackerServer, storageServer);
            NameValuePair[] pairs = new NameValuePair[1];
            pairs[0] = new NameValuePair(file_Name, ext_Name);
            String[] strings = storageClient.upload_file(bytes, ext_Name, null);
            stringBuilder.append(StrUtil.join("/", (Object) strings));
        } catch (IOException | MyException e) {
            ExceptionUtils.error(ImgFeiCode.UPLOAD_ERROR);
        }
        return stringBuilder.toString();
    }




    /**
     * 删除文件
     *
     * @param filePath
     * @return
     */
    private Boolean deleteFile(String filePath) {
        try {
            // 链接FastDFS服务器，创建tracker和Stroage
            ClientGlobal.initByProperties("fastdfs.properties");
            TrackerClient trackerClient = new TrackerClient();
            TrackerServer trackerServer = trackerClient.getTrackerServer();
            String storageServerIp = getStorageServerIp(trackerClient, trackerServer);
            StorageServer storageServer = getStorageServer(storageServerIp);
            StorageClient storageClient = new StorageClient(trackerServer, storageServer);
            int i = storageClient.delete_file("group1", StringUtils.substringAfter(filePath, "group1/"));
            log.info(String.valueOf(i));
            if (i != 0) {
                log.info("删除失败");
                return false;
            }
        } catch (Exception e) {
            log.error("删除文件异常");
            e.printStackTrace();
            return false;
        }
        return true;
    }







    /**
     * 获得可用的storage IP
     *
     * @param trackerClient
     * @param trackerServer
     * @return 返回storage IP
     */
    private static String getStorageServerIp(TrackerClient trackerClient, TrackerServer trackerServer) {
        String storageIp = null;
        if (trackerClient != null && trackerServer != null) {
            try {
                StorageServer storageServer = trackerClient.getStoreStorage(trackerServer, "group1");
                storageIp = storageServer.getInetSocketAddress().getAddress().getHostAddress();
            } catch (IOException | MyException e) {
                e.printStackTrace();
            }
        }
        return storageIp;
    }

    /**
     * 得到Storage服务
     *
     * @param storageIp
     * @return 返回Storage服务
     */
    private static StorageServer getStorageServer(String storageIp) {
        StorageServer storageServer = null;
        if (storageIp != null && !("").equals(storageIp)) {
            try {
                // ip port store_path下标
                storageServer = new StorageServer(storageIp, 23000, 0);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return storageServer;
    }





    /**
     * 文件大小限制
     *
     * @param len
     * @param size
     * @param unit
     * @return
     */
    private static boolean checkFileSize(Long len, int size, String unit) {
        double fileSize = 0;
        if ("B".equals(unit.toUpperCase())) {
            fileSize = (double) len;
        } else if ("K".equals(unit.toUpperCase())) {
            fileSize = (double) len / 1024;
        } else if ("M".equals(unit.toUpperCase())) {
            fileSize = (double) len / 1048576;
        } else if ("G".equals(unit.toUpperCase())) {
            fileSize = (double) len / 1073741824;
        }
        if (fileSize > size) {
            return false;
        }
        return true;
    }
}



